package com.ks.dao;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ks.utils.JDBCUtil;

/**
 * @author 47475
 *
 * @param <T> T传入实体类entity
 */
public abstract class BaseDaoImpl<T> implements BaseDao<T> {
	static Log log = LogFactory.getLog(BaseDaoImpl.class);

	private Class<T> clazz;

	/**
	 * 反射获得类对象
	 */
	@SuppressWarnings("unchecked")
	public BaseDaoImpl() {
		clazz = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	/**
	 * DML操作执行的方法（增删改）
	 * 
	 * @param sql sql语句
	 * @param obj sql查询条件，预编译赋值
	 */
	@Override
	public int executeUpdate(String sql, Object[] obj) {
		Connection conn = null;
		PreparedStatement ps = null;
		int ret = 0;
		try {
			conn = JDBCUtil.getConnection();
			// 3、创建传输对象statmemnt
			// ？不确定:类型、数量
			ps = conn.prepareStatement(sql);
			// 3+、预编译绑定替换数据
			for (int i = 0; i < obj.length; i++) {
				ps.setObject(i + 1, obj[i]);
			}
			// 4、发送sql语句，并且接收返回结果 : DML -> executeUpdate ; DQL -> executeQuery
			ret = ps.executeUpdate();
		} catch (Exception e) {
			log.error("", e);
		} finally {
			JDBCUtil.close(ps, conn);

		}
		return ret;
	}

	/**
	 * DQL操作执行的方法,含有查询条件
	 * 
	 * @param sql sql语句
	 * @param obj sql查询条件，预编译赋值
	 */
	public List<T> executeQuery(String sql, Object[] obj) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		List<T> list = new ArrayList<>();
		try {// 获得连接
			conn = JDBCUtil.getConnection();
			// 3、创建传输对象statmemnt
			ps = conn.prepareStatement(sql);
			// 3+、绑定替换数据
			for (int i = 0; i < obj.length; i++) {
				ps.setObject(i + 1, obj[i]);
			}
			// 4、发送sql语句，并且接收返回结果 : DML -> executeUpdate ; DQL -> executeQuery
			rs = ps.executeQuery();
			// 5、如果返回rs类型的数据，需要将数据转换成list
			// 列名信息
			ResultSetMetaData rsmd = rs.getMetaData();
			// 列的数量
			int columuCount = rsmd.getColumnCount();
			while (rs.next()) {
				// 创建对象
				T t = clazz.newInstance();
				// 封装数据
				for (int i = 0; i < columuCount; i++) {
					/** 把从数据库查出的列名转换成驼峰命名，与实体类相对应 */
					// 列名->属性名->属性对象
					Field f = clazz.getDeclaredField(JDBCUtil.lineToHump(rsmd.getColumnName(i + 1)));
					f.setAccessible(true);
					// 将rs列中的值赋给属性
					/**
					 * 这里处理的有点小问题，oracle的numberJDBC读取出的是BigDecimal类型 因为实体类只存了int类型，所以这里进行了转换避免抛出异常
					 * 有好的方法欢迎赐教
					 */

					if (rs.getObject(i + 1) instanceof BigDecimal) {
						f.set(t, ((BigDecimal) (rs.getObject(i + 1))).intValue());
					} else {
						f.set(t, rs.getObject(i + 1));
					}
				}
				list.add(t);
			}
		} catch (Exception e) {
			log.error("", e);
		} finally {
			JDBCUtil.closeResultSet(rs);
			JDBCUtil.close(ps, conn);
		}
		return list;
	}

	/**
	 * DQL操作执行的方法,不需要查询条件
	 * 
	 * @param sql sql语句
	 * @param obj sql查询条件，预编译赋值
	 */
	@Override
	public List<T> executeQuery(String sql) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		List<T> list = new ArrayList<>();
		try {
			conn = JDBCUtil.getConnection();
			ps = conn.prepareStatement(sql);
			rs = ps.executeQuery();
			ResultSetMetaData rsmd = rs.getMetaData();
			int columuCount = rsmd.getColumnCount();
			while (rs.next()) {
				T t = clazz.newInstance();
				for (int i = 0; i < columuCount; i++) {
					Field f = clazz.getDeclaredField(JDBCUtil.lineToHump(rsmd.getColumnName(i + 1)));
					f.setAccessible(true);
					// 将rs列中的值赋给属性
					if (rs.getObject(i + 1) instanceof BigDecimal) {
						f.set(t, ((BigDecimal) (rs.getObject(i + 1))).intValue());
					} else {
						f.set(t, rs.getObject(i + 1));
					}
				}
				list.add(t);
			}
		} catch (Exception e) {
			log.error("", e);
		} finally {
			JDBCUtil.closeResultSet(rs);
			JDBCUtil.close(ps, conn);
		}
		return list;
	}

	/**
	 * 查询表中记录的数量
	 * 
	 * @param sql 查询sql语句
	 */
	@Override
	public int executeQueryCount(String sql) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		int t = 0;
		try {
			conn = JDBCUtil.getConnection();
			ps = conn.prepareStatement(sql);
			rs = ps.executeQuery();
			rs.next();
			t = rs.getInt(1);
			System.out.println(t);
		} catch (Exception e) {
			log.error("", e);
		} finally {
			JDBCUtil.closeResultSet(rs);
			JDBCUtil.close(ps, conn);
		}
		return t;
	}

}
